package dovs.phases;

import dovs.*;
import dovs.analysis.*;
import dovs.node.*;
import java.util.*;

/** 
 *	Compiler phase to disambiguate ambiguous uses of names and link
 *	the uses of local variables to their definitions.
 */
public aspect Disambiguation extends DepthFirstAdapter {
	/** The declaration of the local variable referenced in this lvalue */
	public ALocalDecl ALocalLvalue.local_decl;


	@Override
	public void caseAAmbiguousNameLvalue(AAmbiguousNameLvalue lvalue) {
		PName name = lvalue.getAmbiguous();
		PLvalue rep = disambiguateName(name);
		if (rep != null) {
			lvalue.replaceBy(rep);
		} else {
			errorVariableNotFound(name);
		}
	}

	@Override 
	public void outAAmbiguousInvokeExp(AAmbiguousInvokeExp exp) {
		PName name = exp.getAmbiguous();

		// Try as lvalue
		PLvalue lvalue = disambiguateName(name);
		if (lvalue != null) {
			ALvalueExp receiver = new ALvalueExp(lvalue);
			ANonstaticInvokeExp invoke = new ANonstaticInvokeExp(receiver, exp.getName(), exp.getArgs());
			exp.replaceBy(invoke);
			return;
		}
		// TODO handle the ambiguous name as a type, cf. rules 3,5 of TypeChecking slide 44-45.
	}
	/**
	 * Returns a PLvalue of the disambiguated name, cf. rules 1-4 and 1-2,4,6 of
	 * TypeChecking slides 43 and 44-45, respectively.
	 * @param name
	 * 		the ambiguous name (not including method name for invocations)
	 * @return
	 * 		the resulting PLvalue or null if the name could not be disambiguated
	 */
	private PLvalue disambiguateName(PName name) {
		// TODO 
		return null;
	}


	// /////////////////////////////////////////////////////////////////////////
	// ERROR MESSAGES
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * Reports the error of an illegal forward reference of a nonstatic field.
	 * 
	 * @param field
	 *            the field declaration of the refered field
	 */
	@SuppressWarnings("unused")
	private static void errorIllegalForwardFieldReference(AFieldDecl field) {
		Errors.error(ErrorType.ILLEGAL_FORWARD_FIELD_REFERENCE,
				field.getName(), "Illegal forward reference of instance field "
						+ field.getName().getText(), false);
	}

	/**
	 * Reports the error of an illegal forward reference of a static field.
	 * 
	 * @param field
	 *            the field declaration of the refered field
	 */
	@SuppressWarnings("unused")
	private static void errorIllegalForwardStaticFieldReference(AFieldDecl field) {
		Errors.error(ErrorType.ILLEGAL_FORWARD_STATIC_FIELD_REFERENCE, field
				.getName(), "Illegal forward reference of static field "
				+ field.getName().getText(), false);
	}

	/**
	 * If compiling with the {@code -joos1} option, reports the error that
	 * implicit this class is used for static fields.
	 * 
	 * @param field_id
	 *            the identier holding the field name
	 */
	@SuppressWarnings("unused")
	private static void checkJoos1ImplicitThisClassStaticField(
			TIdentifier field_id) {
		Errors.checkJoos1(ErrorType.JOOS1_IMPLICIT_THIS_CLASS_STATIC_FIELD,
				field_id, "Implicit this class for static fields");
	}

	/**
	 * Reports the error that a variable could not be found through the
	 * disambiguation rules.
	 * 
	 * @param name
	 *            the name of the variable
	 */
	@SuppressWarnings("unused")
	private static void errorVariableNotFound(PName name) {
		Errors.error(ErrorType.VARIABLE_NOT_FOUND, name.getToken(),
				"Could not find variable " + name.nameText(), false);
	}

	/**
	 * Reports the error that a name could not resolved to neither a variable
	 * nor a type through the disambiguation rules.
	 * 
	 * @param name
	 *            the name of the variable or type
	 */
	@SuppressWarnings("unused")
	private static void errorVariableOrTypeNotFound(PName name) {
		Errors.error(ErrorType.VARIABLE_OR_TYPE_NOT_FOUND, name.getToken(),
				"Could not find variable or type " + name.nameText(), false);
	}

}
